package com.unicom.mec.deploy.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.unicom.mec.deploy.mapper.ApplicationDeployMapper;
import com.unicom.mec.deploy.mapper.ExampleDeployMapper;
import com.unicom.mec.deploy.mapper.TemplateDeployMapper;
import com.unicom.mec.deploy.model.ApplicationDeploy;
import com.unicom.mec.deploy.model.ExampleDeploy;
import com.unicom.mec.deploy.model.TemplateDeploy;
import com.unicom.mec.deploy.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 应用部署业务层实现
 *
 * @author 刘亮武
 * @date 2020年06月18日
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class DeployServiceImpl implements DeployService {

    public static final String SUCCESS_STATUS = "200";

    @Value("${deploy.host}")
    private String host;
    @Value("${deploy.api.deployment}")
    private String deploymentApi;
    @Value("${deploy.api.delete}")
    private String deleteApi;

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ApplicationDeployMapper applicationDeployMapper;
    @Autowired
    private TemplateDeployMapper templateDeployMapper;
    @Autowired
    private ExampleDeployMapper exampleDeployMapper;

    @Override
    public void addApplicationDeploy(ApplicationDeployVo applicationDeployVo) {
        long start = System.currentTimeMillis();
        Long createId = 1271322350203121664L;
        Date time = new Date();
        Long applicationDeployId = IdWorker.getId();
        ApplicationDeploy applicationDeploy = new ApplicationDeploy();
        applicationDeploy.setId(applicationDeployId);
        applicationDeploy.setTenantId(applicationDeployVo.getTenantId());
        applicationDeploy.setProjectId(applicationDeployVo.getProjectId());
        applicationDeploy.setApplicationId(applicationDeployVo.getApplicationId());
        applicationDeploy.setApplicationName(applicationDeployVo.getApplicationName());
        applicationDeploy.setCreateId(createId);
        applicationDeploy.setCreateTime(time);
        applicationDeployMapper.insert(applicationDeploy);
        applicationDeployVo.getTemplates().forEach(templateDeployVo -> {
            Long templateDeployId = IdWorker.getId();
            TemplateDeploy templateDeploy = new TemplateDeploy();
            templateDeploy.setId(templateDeployId);
            templateDeploy.setApplicationDeployId(applicationDeployId);
            templateDeploy.setTemplateId(templateDeployVo.getTemplateId());
            templateDeploy.setTemplateName(templateDeployVo.getTemplateName());
            templateDeploy.setTemplateDesc(templateDeployVo.getTemplateDesc());
            templateDeploy.setChartPath(templateDeployVo.getChartPath());
            templateDeploy.setVariableDeployment(templateDeployVo.getVariableDeployment());
            templateDeploy.setVersion(templateDeployVo.getVersion());
            templateDeploy.setCreateId(createId);
            templateDeploy.setCreateTime(time);
            templateDeployMapper.insert(templateDeploy);
            templateDeployVo.getExamples().forEach(exampleDeployVo -> {
                ExampleDeploy exampleDeploy = new ExampleDeploy();
                exampleDeploy.setId(IdWorker.getId());
                exampleDeploy.setApplicationDeployId(applicationDeployId);
                exampleDeploy.setTemplateDeployId(templateDeployId);
                exampleDeploy.setCpu(0);
                exampleDeploy.setMemory(0);
                exampleDeploy.setEdgeNodeId(exampleDeployVo.getEdgeNodeId());
                exampleDeploy.setEdgeNodeKey(exampleDeployVo.getEdgeNodeKey());
                exampleDeploy.setEdgeEndpointId(exampleDeployVo.getEdgeEndpointId());
                exampleDeploy.setEdgeEndpointKey(exampleDeployVo.getEdgeEndpointKey());
                exampleDeploy.setCreateId(createId);
                exampleDeploy.setCreateTime(time);
                exampleDeployMapper.insert(exampleDeploy);
                deployToK3S(templateDeploy.getVariableDeployment(), templateDeploy.getChartPath(), exampleDeploy);
            });
        });
        System.out.println("time:"+(System.currentTimeMillis()-start));
    }

    /**
     * 向k3s部署应用
     *
     * @param variable      参数信息
     * @param chartPath     chart包路径
     * @param exampleDeploy 实例部署信息
     */
    void deployToK3S(String variable, String chartPath, ExampleDeploy exampleDeploy) {
        //请求地址
        String url = host+deploymentApi;
        //入参
        RequestBean requestBean = new RequestBean();
        requestBean.setNodeSelector(exampleDeploy.getEdgeNodeKey());
        requestBean.setName("chart-" + exampleDeploy.getId());
        requestBean.setChartName(chartPath);
        Map<String, String> env = new HashMap<>();
        TemplateBean templateBean = JSON.parseObject(variable, TemplateBean.class);
        templateBean.getCommonVariable().forEach(commonVariable -> {
            env.put(commonVariable.getKey(), commonVariable.getValue());
        });
        templateBean.getEnvironmentVariable().forEach(environmentVariable -> {
            env.put(environmentVariable.getKey(), environmentVariable.getValue());
        });
        requestBean.setEnv(env);

        ResponseBean responseBean = restTemplate.postForObject(url, requestBean, ResponseBean.class);
    }

    private void deleteApplication(Long id) {
        // 定义模板删除成功数量
        AtomicInteger templateCount = new AtomicInteger();
        // 根据部署应用主键查询应用关联的所有部署模板
        QueryWrapper<TemplateDeploy> templateQuery = new QueryWrapper<>();
        templateQuery.eq("application_deploy_id",id);
        List<TemplateDeploy> templateDeploys = templateDeployMapper.selectList(templateQuery);
        templateDeploys.forEach(templateDeploy -> {
            // 定义实例删除成功数量
            AtomicInteger exampleCount = new AtomicInteger();
            // 根据部署应用主键和应用部署模板主键查询所有实例节点信息
            QueryWrapper<ExampleDeploy> exampleQuery = new QueryWrapper<>();
            exampleQuery.eq("application_deploy_id",id);
            exampleQuery.eq("template_deploy_id",templateDeploy.getId());
            List<ExampleDeploy> exampleDeploys = exampleDeployMapper.selectList(exampleQuery);
            exampleDeploys.forEach(exampleDeploy -> {
                //请求地址
                String url = host+String.format(deleteApi,"chart-" + exampleDeploy.getId());
                System.out.println(url);
                ResponseEntity<ResponseBean> responseBean = restTemplate.exchange(url, HttpMethod.DELETE,null, ResponseBean.class);
                System.out.println(responseBean.getBody().getReturnCode());
                if(SUCCESS_STATUS.equals(responseBean.getBody().getReturnCode())){
                    exampleDeployMapper.deleteById(exampleDeploy.getId());
                    exampleCount.getAndIncrement();
                }
            });
            // 如果所有实例节点信息已删除就删除部署模板信息
            if(exampleDeploys.size() == exampleCount.get()){
                templateDeployMapper.deleteById(templateDeploy.getId());
                templateCount.getAndIncrement();
            }
        });
        // 如果所有模板信息已删除就删除部署信息
        if(templateDeploys.size() == templateCount.get()){
            applicationDeployMapper.deleteById(id);
        }
    }

    @Override
    public void deleteApplicationDeploy(Long id) {
        deleteApplication(id);
    }

    @Override
    public void deleteApplicationDeployByProjectId(Long projectId) {
        // 根据项目主键查询所有部署应用
        QueryWrapper<ApplicationDeploy> applicationQuery = new QueryWrapper<>();
        applicationQuery.eq("project_id",projectId);
        List<ApplicationDeploy> applicationDeploys = applicationDeployMapper.selectList(applicationQuery);
        applicationDeploys.forEach(applicationDeploy -> {
            deleteApplication(applicationDeploy.getId());
        });
    }

    @Override
    public Page<ApplicationVo> findApplications(String applicationName, Long projectId, Integer page, Integer pageSize) {
        Page searchPage = new Page(page, pageSize);
        return applicationDeployMapper.findApplications(searchPage, projectId, applicationName);
    }
}
